// Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef _REMOTE_VIDEO_ENCODER_H_
#define _REMOTE_VIDEO_ENCODER_H_

#include <atomic>
#include <mutex>
#include "VideoEngine.h"
#include "VideoEncoderParam.h"


#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#ifdef __cplusplus
};
#endif

// 这个类不是线程安全的，设计为单线程调用
class RemoteVideoEncoder {
public:
    RemoteVideoEncoder();
    virtual ~RemoteVideoEncoder();
    static RemoteVideoEncoder *GetInstance();
    static int DestroyInstance();
    void SetStatus(const EngineStat newStatus);
    EngineStat GetStatus() const;
    void SetStatics(const EncoderStatistics statics);
    EncoderStatistics GetStatics() const;
    int SetParam(VideoEncoderParam &param);
    bool SetEncoderName();
    int InitEncoder(VideoEncoderParam &param);
    int StartEncoder();
    int StopEncoder();
    void ResetEncoder();
    int EncodeOneFrame(uint8_t *src, uint32_t length, std::pair<uint8_t *, uint32_t> &outData,
                      VideoParamExt &outVideoParam, bool isRepeat);
    unsigned int getCurrentFPS(uint64_t &currentTs);
    bool GetResetFlag();
    int DestroyEncoder();
    void SetOpt(std::string key, std::string value);
    void reloadConfig();
    
    std::atomic<bool> m_keyFrameFlag{false};
    
    std::atomic<bool> m_firstModeFlag{true};
    int m_rcMode = -1;
private:
    const char *encoderName = "libx264";
    AVFrame *frame = nullptr;
    AVCodecContext *avCtx = nullptr;
    unsigned int ptsNo = 1;
    AVPacket *encPkt = nullptr;
    AVCodec *codec = nullptr;
    static RemoteVideoEncoder *g_instance;
    std::atomic<bool> m_resetFlag{false};
    std::atomic<EngineStat> m_status{VMI_ENCODE_ENGINE_INVALID};
    EncoderStatistics m_encoderStatics = {};
    uint64_t m_lastTime = 0;
    uint32_t m_totalCountPerSecond = 0;
    uint32_t m_frameCount = 0;
    uint32_t m_repeatFrameCount = 0;
    uint32_t m_lastEncodeTime = 0;
    uint32_t m_lastRepeatEncodeTime = 0;
    uint32_t m_lastFPS = 0;
    uint32_t m_frameRate = 30;
    uint32_t m_bitrate = 5000000;
    uint32_t m_gopSize = 30;
    uint32_t m_profile = 77;
    uint32_t m_width = 720;
    uint32_t m_height = 1280;
    uint32_t m_frameSize = 0;
    bool mIsReadyForRepeat = false;
    int m_repeatWidth = 0;
    int m_repeatHeight = 0;
    uint32_t m_repeatFPS = 0;
    uint32_t m_rcBufferSize = 0;
    uint8_t m_cpuCnt = 2;
    bool m_sliceBased = 1;
    std::string m_preset = "veryfast";
    std::string m_tune = "zerolatency";
    EncodeType m_encoderType = ENCODER_TYPE_DEFAULT;
    EncodeFrameType m_frameType = FRAME_TYPE_H264;
    void InitRCParamsCPU(VideoEncoderParam &param);
    void InitRCParamsGPU(VideoEncoderParam &param);
    void InitParamsCPU(VideoEncoderParam &param);
    void InitParamsGPU(VideoEncoderParam &param);
    void InitParams(VideoEncoderParam &param);
    void UpdateForOneSecond(uint64_t currentTime);
};

#endif  // _CPU_VIDEO_ENCODER_H_
